package com.zlq.cn.service.ai;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlq.cn.bootstrap.SignApiBootstrap;
import com.zlq.cn.cache.RedisCacheService;
import com.zlq.cn.config.Config;
import com.zlq.cn.config.OkhttpConfig;
import com.zlq.cn.entity.BaiduAi;
import com.zlq.cn.entity.FanyiUser;
import com.zlq.cn.mapper.ai.BaiduAiMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service("baiduAiService")
public class BaiduAiService extends ServiceImpl<BaiduAiMapper, BaiduAi> implements ApplicationRunner {

    private static final String API_KEY = "pwb4xcUH2mpti3KPq4GwbrHf";
    private static final String SECRET_KEY = "g9TF0hrdmS8QwUOrhrvWEoALkybAzjst";
    private static final String AI_BAIDU_TOKEN_CACHE_KEY = "AI:BAIDU:TOKEN";
    private static final String TXT2IMG = "txt2img";

    private boolean isRun = false;

    @Resource
    private RedisCacheService redisCacheService;

    @Resource
    private AiCommonService aiCommonService;

    public BaiduAi txt2img(JSONObject param) {
        FanyiUser fanyiUser = aiCommonService.checkUserNum(Config.BAIDU_AI);
        JSONObject result = request(param, "https://aip.baidubce.com/rpc/2.0/ernievilg/v1/txt2img");
        Integer taskId = result.getJSONObject("data").getInteger("taskId");
        BaiduAi txt2img = new BaiduAi()
                .setTaskId(taskId)
                .setType(TXT2IMG)
                .setUserImei(fanyiUser.getFanyiUserImei())
                .setStatus(0)
                .setQueryUrl("https://aip.baidubce.com/rpc/2.0/ernievilg/v1/getImg")
                .setRequestParam(param.toJSONString())
                .setResult(result.toJSONString())
                .setCreateTime(LocalDateTime.now())
                .setCreateDate(LocalDate.now());
        super.save(txt2img);
        isRun = true;
        return txt2img;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        isRun = true;
        runQueryTask();
    }

    @Scheduled(fixedDelay = 2000)
    public void runQueryTask() {
        if (isRun) {
            List<BaiduAi> list = super.lambdaQuery()
                    .eq(BaiduAi::getStatus, 0)
                    .list();
            if (CollectionUtils.isNotEmpty(list)) {
                for (BaiduAi baiduAi : list) {
                    try {
                        queryTask(baiduAi);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } else {
                isRun = false;
            }
        }
    }

    public Page<BaiduAi> txt2imgList(Page<BaiduAi> page) {
        FanyiUser fanyiUser = SignApiBootstrap.requestFanYiUser(Config.PROJECT_AI);
        return super.lambdaQuery()
                .eq(BaiduAi::getType, TXT2IMG)
                .eq(BaiduAi::getUserImei, fanyiUser.getFanyiUserImei())
                .orderByDesc(BaiduAi::getCreateTime)
                .page(page);
    }

    private BaiduAi queryTask(BaiduAi baiduAi) {
        JSONObject param = new JSONObject();
        param.put("taskId", baiduAi.getTaskId());
        JSONObject result = request(param, baiduAi.getQueryUrl());
        if (result.containsKey("data")) {
            baiduAi.setStatus(result.getJSONObject("data").getInteger("status"));
            baiduAi.setResult(result.toJSONString());
            super.update(baiduAi, new LambdaUpdateWrapper<BaiduAi>()
                    .eq(BaiduAi::getTaskId, baiduAi.getTaskId())
                    .eq(BaiduAi::getType, baiduAi.getType()));
        } else if ("invalid parameter(s)".equals(result.getString("error_msg"))) {
            super.removeById(baiduAi.getTaskId());
        }
        return baiduAi;
    }

    public JSONObject request(JSONObject param, String url) {
        MediaType mediaType = MediaType.parse("application/json");
        okhttp3.RequestBody body = okhttp3.RequestBody.create(param.toJSONString(), mediaType);
        Request request = new Request.Builder()
                .url(url + "?access_token=" + getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        try {
            return JSON.parseObject(OkhttpConfig.okHttpClient.newCall(request).execute().body().string());
        } catch (IOException e) {
            throw new RuntimeException("token获取失败");
        }
    }

    /**
     * 从用户的AK，SK生成鉴权签名（Access Token）
     *
     * @return 鉴权签名（Access Token）
     * @throws IOException IO异常
     */
    private String getAccessToken() {
        String accessToken = redisCacheService.get(AI_BAIDU_TOKEN_CACHE_KEY);
        if (StringUtils.isBlank(accessToken)) {
            MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
            okhttp3.RequestBody body = okhttp3.RequestBody
                    .create("grant_type=client_credentials&client_id=" + API_KEY
                            + "&client_secret=" + SECRET_KEY, mediaType);
            Request request = new Request.Builder()
                    .url("https://aip.baidubce.com/oauth/2.0/token")
                    .method("POST", body)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded")
                    .build();
            try {
                Response response = OkhttpConfig.okHttpClient.newCall(request).execute();
                JSONObject jsonObject = JSON.parseObject(response.body().string());
                log.info(jsonObject.toJSONString());
                accessToken = jsonObject.getString("access_token");
                Long expiresIn = jsonObject.getLong("expires_in");
                if (StringUtils.isBlank(accessToken)) {
                    throw new RuntimeException("token获取失败");
                }
                if (expiresIn == null) {
                    expiresIn = 2592000L;
                }
                expiresIn = expiresIn - 60 * 60;
                redisCacheService.set(AI_BAIDU_TOKEN_CACHE_KEY, accessToken, expiresIn);
            } catch (Exception e) {
                log.error("百度请求Token失败", e);
                throw new RuntimeException("token获取失败");
            }
        }
        return accessToken;
    }
}
